package com.kuangjia.conferenceroomrental.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kuangjia.conferenceroomrental.entity.Reservation;
import com.kuangjia.conferenceroomrental.entity.Room;
import com.kuangjia.conferenceroomrental.entity.User;
import com.kuangjia.conferenceroomrental.mapper.ReservationMapper;
import com.kuangjia.conferenceroomrental.mapper.RoomMapper;
import com.kuangjia.conferenceroomrental.mapper.UserMapper;
import com.kuangjia.conferenceroomrental.service.ReservationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 预约服务实现类
 */
@Service
public class ReservationServiceImpl implements ReservationService {
    
    @Autowired
    private ReservationMapper reservationMapper;
    
    @Autowired
    private RoomMapper roomMapper;
    
    @Autowired
    private UserMapper userMapper;
    
    @Override
    @Transactional
    public Reservation createReservation(Reservation reservation) {
        // 设置创建时间和更新时间
        LocalDateTime now = LocalDateTime.now();
        reservation.setCreatedAt(now);
        reservation.setUpdatedAt(now);
        
        // 设置初始状态为待审批
        if (reservation.getStatus() == null) {
            reservation.setStatus("PENDING");
        }
        
        // 插入数据库
        reservationMapper.insert(reservation);
        
        // 填充关联对象
        fillAssociations(reservation);
        
        return reservation;
    }
    
    @Override
    public Reservation getReservationById(Long id) {
        Reservation reservation = reservationMapper.selectById(id);
        if (reservation != null) {
            fillAssociations(reservation);
        }
        return reservation;
    }
    
    @Override
    public List<Reservation> getAllReservations() {
        List<Reservation> reservations = reservationMapper.selectList(null);
        return reservations.stream()
                .map(this::fillAssociations)
                .collect(Collectors.toList());
    }
    
    @Override
    public IPage<Reservation> getReservationsByPage(Page<Reservation> page) {
        IPage<Reservation> pageResult = reservationMapper.selectPage(page, null);
        pageResult.getRecords().forEach(this::fillAssociations);
        return pageResult;
    }
    
    @Override
    public List<Reservation> getReservationsByUserId(Long userId) {
        List<Reservation> reservations = reservationMapper.selectByUserId(userId);
        return reservations.stream()
                .map(this::fillAssociations)
                .collect(Collectors.toList());
    }
    
    @Override
    public IPage<Reservation> getReservationsByUserIdPage(Page<Reservation> page, Long userId) {
        LambdaQueryWrapper<Reservation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Reservation::getUserId, userId)
                   .orderByDesc(Reservation::getCreatedAt);
        IPage<Reservation> pageResult = reservationMapper.selectPage(page, queryWrapper);
        pageResult.getRecords().forEach(this::fillAssociations);
        return pageResult;
    }
    
    @Override
    public List<Reservation> getReservationsByRoomId(Long roomId) {
        List<Reservation> reservations = reservationMapper.selectByRoomId(roomId);
        return reservations.stream()
                .map(this::fillAssociations)
                .collect(Collectors.toList());
    }
    
    @Override
    public IPage<Reservation> getReservationsByRoomIdPage(Page<Reservation> page, Long roomId) {
        LambdaQueryWrapper<Reservation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Reservation::getRoomId, roomId)
                   .orderByAsc(Reservation::getStartTime);
        IPage<Reservation> pageResult = reservationMapper.selectPage(page, queryWrapper);
        pageResult.getRecords().forEach(this::fillAssociations);
        return pageResult;
    }
    
    @Override
    public List<Reservation> getReservationsByStatus(String status) {
        List<Reservation> reservations = reservationMapper.selectByStatus(status);
        return reservations.stream()
                .map(this::fillAssociations)
                .collect(Collectors.toList());
    }
    
    @Override
    public IPage<Reservation> getReservationsByStatusPage(Page<Reservation> page, String status) {
        LambdaQueryWrapper<Reservation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Reservation::getStatus, status)
                   .orderByDesc(Reservation::getCreatedAt);
        IPage<Reservation> pageResult = reservationMapper.selectPage(page, queryWrapper);
        pageResult.getRecords().forEach(this::fillAssociations);
        return pageResult;
    }
    
    @Override
    @Transactional
    public Reservation updateReservation(Reservation reservation) {
        // 设置更新时间
        reservation.setUpdatedAt(LocalDateTime.now());
        
        // 更新数据库
        reservationMapper.updateById(reservation);
        
        // 填充关联对象
        fillAssociations(reservation);
        
        return reservation;
    }
    
    @Override
    @Transactional
    public void deleteReservation(Long id) {
        reservationMapper.deleteById(id);
    }
    
    @Override
    public boolean hasTimeConflict(Long roomId, LocalDateTime startTime, LocalDateTime endTime) {
        // 直接进行SQL查询检测冲突
        int count = reservationMapper.checkTimeConflict(roomId, startTime, endTime);
        
        System.out.println("===============================================");
        System.out.println("【时间冲突检测结果】");
        System.out.println("【会议室ID】: " + roomId);
        System.out.println("【开始时间】: " + startTime);
        System.out.println("【结束时间】: " + endTime);
        System.out.println("【冲突数量】: " + count);
        
        // 仅用于调试 - 获取当前已有预约
        try {
            List<Reservation> allReservations = reservationMapper.selectList(
                new LambdaQueryWrapper<Reservation>()
                    .eq(Reservation::getRoomId, roomId)
                    .in(Reservation::getStatus, Arrays.asList("PENDING", "APPROVED"))
            );
            
            System.out.println("【当前预约记录总数】: " + allReservations.size());
            for (Reservation r : allReservations) {
                boolean overlaps = !(endTime.isBefore(r.getStartTime()) || startTime.isAfter(r.getEndTime()));
                System.out.println("  - ID: " + r.getId() + 
                                  ", 状态: " + r.getStatus() + 
                                  ", 时间: " + r.getStartTime() + " 至 " + r.getEndTime() + 
                                  ", 手工判断冲突: " + overlaps);
            }
            
            // 再次使用精确查询进行验证
            List<Reservation> exactMatches = findReservationsInTimeRange(roomId, startTime, endTime);
            System.out.println("【精确查询冲突结果】: " + exactMatches.size());
            exactMatches.forEach(r -> System.out.println("  - 冲突ID: " + r.getId() + 
                                                       ", 状态: " + r.getStatus() + 
                                                       ", 时间: " + r.getStartTime() + " 至 " + r.getEndTime()));
        } catch (Exception e) {
            System.err.println("查询过程中发生错误: " + e.getMessage());
        }
        System.out.println("===============================================");
        
        return count > 0;
    }
    
    @Override
    public boolean hasTimeConflictByRoomName(String roomName, LocalDateTime startTime, LocalDateTime endTime) {
        // 直接通过会议室名称查询冲突
        int count = reservationMapper.checkTimeConflictByRoomName(roomName, startTime, endTime);
        
        System.out.println("会议室名称时间冲突检测结果: 会议室名称=" + roomName + 
                          ", 开始时间=" + startTime + 
                          ", 结束时间=" + endTime + 
                          ", 冲突数量=" + count);
        
        return count > 0;
    }
    
    @Override
    public List<Reservation> getConflictingReservations(Long roomId, LocalDateTime startTime, LocalDateTime endTime) {
        // 获取冲突的预约列表
        List<Reservation> reservations = reservationMapper.getConflictingReservations(roomId, startTime, endTime);
        
        System.out.println("获取到的冲突预约数量: " + reservations.size());
        reservations.forEach(r -> System.out.println(" - 冲突预约ID: " + r.getId() + 
                                                   ", 会议室: " + r.getRoomId() + 
                                                   ", 开始时间: " + r.getStartTime() + 
                                                   ", 结束时间: " + r.getEndTime() + 
                                                   ", 状态: " + r.getStatus()));
        
        return reservations.stream()
                .map(this::fillAssociations)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<Reservation> getConflictingReservationsByRoomName(String roomName, LocalDateTime startTime, LocalDateTime endTime) {
        // 通过会议室名称获取冲突预约列表
        List<Reservation> reservations = reservationMapper.getConflictingReservationsByRoomName(roomName, startTime, endTime);
        
        System.out.println("根据会议室名称获取到的冲突预约数量: " + reservations.size());
        reservations.forEach(r -> System.out.println(" - 冲突预约ID: " + r.getId() + 
                                                   ", 会议室: " + roomName + 
                                                   ", 开始时间: " + r.getStartTime() + 
                                                   ", 结束时间: " + r.getEndTime() + 
                                                   ", 状态: " + r.getStatus()));
        
        return reservations.stream()
                .map(this::fillAssociations)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<Reservation> findReservationsInTimeRange(Long roomId, LocalDateTime startTime, LocalDateTime endTime) {
        // 使用精确时间范围查询
        List<Reservation> reservations = reservationMapper.findReservationsInTimeRange(roomId, startTime, endTime);
        
        System.out.println("精确时间范围查询结果: " + reservations.size());
        reservations.forEach(r -> System.out.println(" - 预约ID: " + r.getId() + 
                                                   ", 开始时间: " + r.getStartTime() + 
                                                   ", 结束时间: " + r.getEndTime() + 
                                                   ", 状态: " + r.getStatus()));
        
        return reservations.stream()
                .map(this::fillAssociations)
                .collect(Collectors.toList());
    }
    
    @Override
    @Transactional
    public Reservation approveReservation(Long id) {
        Reservation reservation = reservationMapper.selectById(id);
        if (reservation != null) {
            reservation.setStatus("APPROVED");
            reservation.setUpdatedAt(LocalDateTime.now());
            reservationMapper.updateById(reservation);
            fillAssociations(reservation);
        }
        return reservation;
    }
    
    @Override
    @Transactional
    public Reservation rejectReservation(Long id) {
        Reservation reservation = reservationMapper.selectById(id);
        if (reservation != null) {
            reservation.setStatus("REJECTED");
            reservation.setUpdatedAt(LocalDateTime.now());
            reservationMapper.updateById(reservation);
            fillAssociations(reservation);
        }
        return reservation;
    }
    
    @Override
    @Transactional
    public Reservation cancelReservation(Long id) {
        Reservation reservation = reservationMapper.selectById(id);
        if (reservation != null) {
            reservation.setStatus("CANCELLED");
            reservation.setUpdatedAt(LocalDateTime.now());
            reservationMapper.updateById(reservation);
            fillAssociations(reservation);
        }
        return reservation;
    }
    
    /**
     * 填充关联对象
     */
    private Reservation fillAssociations(Reservation reservation) {
        if (reservation.getRoomId() != null) {
            Room room = roomMapper.selectById(reservation.getRoomId());
            reservation.setRoom(room);
        }
        
        if (reservation.getUserId() != null) {
            User user = userMapper.selectById(reservation.getUserId());
            reservation.setUser(user);
        }
        
        return reservation;
    }
    
    /**
     * 将ISO格式的UTC时间字符串转换为LocalDateTime对象
     * 用于前端传入的ISO 8601格式时间处理
     */
    public LocalDateTime parseIsoDateTime(String isoDateTimeStr) {
        if (isoDateTimeStr == null || isoDateTimeStr.trim().isEmpty()) {
            return null;
        }
        
        try {
            return LocalDateTime.parse(isoDateTimeStr, DateTimeFormatter.ISO_DATE_TIME);
        } catch (Exception e) {
            System.err.println("解析ISO日期时间失败: " + e.getMessage());
            throw new IllegalArgumentException("无效的ISO日期时间格式: " + isoDateTimeStr);
        }
    }
    
    /**
     * 将LocalDateTime格式化为ISO 8601 UTC时间字符串
     * 用于返回给前端的时间格式
     */
    public String formatToIsoDateTime(LocalDateTime dateTime) {
        if (dateTime == null) {
            return null;
        }
        
        try {
            return dateTime.format(DateTimeFormatter.ISO_DATE_TIME);
        } catch (Exception e) {
            System.err.println("格式化为ISO日期时间失败: " + e.getMessage());
            return null;
        }
    }
    
    /**
     * 根据ISO格式的时间字符串检查时间冲突
     * 直接支持前端传入的格式
     */
    public boolean hasTimeConflictIso(Long roomId, String isoStartTime, String isoEndTime) {
        LocalDateTime startTime = parseIsoDateTime(isoStartTime);
        LocalDateTime endTime = parseIsoDateTime(isoEndTime);
        
        System.out.println("检查时间冲突 (ISO格式转换): ");
        System.out.println("  - 原始开始时间: " + isoStartTime);
        System.out.println("  - 原始结束时间: " + isoEndTime);
        System.out.println("  - 转换后开始时间: " + startTime);
        System.out.println("  - 转换后结束时间: " + endTime);
        System.out.println("  - 数据库格式开始时间: " + startTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        System.out.println("  - 数据库格式结束时间: " + endTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        
        return hasTimeConflict(roomId, startTime, endTime);
    }
    
    /**
     * 根据ISO格式的时间字符串获取冲突的预约
     * 直接支持前端传入的格式
     */
    public List<Reservation> getConflictingReservationsIso(Long roomId, String isoStartTime, String isoEndTime) {
        LocalDateTime startTime = parseIsoDateTime(isoStartTime);
        LocalDateTime endTime = parseIsoDateTime(isoEndTime);
        
        return getConflictingReservations(roomId, startTime, endTime);
    }
}